package lol.clann.minecraft.springboot.api.bukkit.utils;

import lol.clann.minecraft.springboot.api.bukkit.constant.FluidCollisionOptionEnum;
import lol.clann.minecraft.springboot.api.bukkit.model.BoundingBox;
import lol.clann.minecraft.springboot.api.bukkit.model.RayTraceResult;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;

import javax.annotation.Nullable;
import java.util.List;
import java.util.function.Predicate;

/**
 *
 * @author pyz
 * @date 2019/5/2 5:55 PM
 */
public interface WorldUtils {
    /**
     * Bukkit转NMS
     * @param world
     * @param <T>
     * @return
     */
    <T> T toNMS(World world);

    /**
     * NMS转Bukkit
     * @param nmsWorld
     * @param <T>
     * @return
     */
    <T> World toBukkit(T nmsWorld);

    /**
     * 获取指定位置的TileEntity
     *
     * @param world
     * @param x
     * @param y
     * @param z
     * @param <T>
     * @return
     */
    <T> T getTileEntity(World world, int x, int y, int z);

    /**
     * 获取指定位置的TileEntity
     * @param location
     * @param <T>
     * @return
     */
    <T> T getTileEntity(Location location);

    /**
     * 获取指定位置的TileEntity
     * @param block
     * @param <T>
     * @return
     */
    <T> T getTileEntity(Block block);

    /**
     * 判断区块是否加载
     *
     * @return
     */
    default public boolean isChunkLoaded(Location loc) {
        return isChunkLoaded(loc.getWorld(), loc.getBlockX() >> 4, loc.getBlockZ() >> 4);
    }

    /**
     * 判断区块是否加载
     * @param world
     * @param chunkX 区块坐标X = 方块坐标X >> 4
     * @param chunkZ 区块坐标X = 方块坐标X >> 4
     * @return
     */
    default public boolean isChunkLoaded(World world, int chunkX, int chunkZ) {
        return world.isChunkLoaded(chunkX, chunkZ);
    }

    /**
     * 获取World的DIM编号
     * @param world
     * @return
     */
    int getDimension(World world);

    /**
     * 根据DIM编号获取World
     * @param demension
     * @return
     */
    World getByDimension(int demension);

    /**
     * 获取指定世界的TPS
     *
     * @param world
     * @return
     */
    double getTps(World world);

    /**
     * 光线追踪,获取第一个碰到的实体
     *
     * @param start 起始位置
     * @param direction 方向
     * @param maxDistance 距离
     * @param filter 实体过滤条件
     * @return
     */
    @Nullable
    Entity rayTraceEntity(Location start, Vector direction, double maxDistance, Predicate<Entity> filter);

    /**
     * 光纤追踪,获取碰到的所有实体
     *
     * @param start 起始位置
     * @param direction 方向
     * @param maxDistance 距离
     * @param filter 实体过滤条件
     * @return
     */
    List<Entity> rayTraceEntities(Location start, Vector direction, double maxDistance, Predicate<Entity> filter);

    /**
     * 光线追踪,获取碰到的第一个满足条件的方块
     * @param start 起始位置
     * @param direction 方向
     * @param maxDistance 距离
     * @param fluidCollisionMode
     * @param ignorePassableBlocks 忽略不可碰撞的方块
     * @return
     */
    RayTraceResult rayTraceBlocks(Location start, Vector direction, double maxDistance, FluidCollisionOptionEnum fluidCollisionMode, boolean ignorePassableBlocks);

    /**
     * 搜索指定范围内的实体
     *
     * @param world
     * @param box 用碰撞箱指定范围
     * @param filter 实体过滤条件
     * @return
     */
    List<Entity> findEntitiesInBoundingBox(World world, BoundingBox box, Predicate<Entity> filter);
}
